package top.whysu.rongcloud.global;

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import top.whysu.rongcloud.exception.BusinessException;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;


/**
 * @author
 * @version 1.00.00
 * @description 操作日志记录
 * @copyright
 * @company
 * @date 2019-12-09 14:49
 */
@Aspect
@Component
@Order(value = 1)
public class LogAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(LogAspect.class);

    private static String[] types = {"java.lang.Integer", "java.lang.Double",
            "java.lang.Float", "java.lang.Long", "java.lang.Short",
            "java.lang.Byte", "java.lang.Boolean", "java.lang.Char",
            "java.lang.String", "java.math.BigDecimal", "int", "double", "long", "short", "byte",
            "boolean", "char", "float"};

    /**
     * 被执行的业务切点
     *
     * @param
     * @return
     * @author
     */
    @Pointcut("execution(* top.whysu.rongcloud.service..*.*(..))")
    public void pointCut() {
    }

    /**
     * 将参数转换成json
     *
     * @param args 参数集合
     * @return
     * @author
     */
    private Map<String, Map> getArgsMap(Object[] args) {
        Map<String, Map> clazzMap = new HashMap<>();
        try {
            for (int k = 0; k < args.length; k++) {
                if (args[k] == null) {
                    continue;
                }
                Map<String, Object> map = new HashMap<>();
                // 获取对象名称k
                String targetName = args[k].getClass().getTypeName();
                boolean flag = false;
                for (String type : types) {
                    // 判断是否是基础类型
                    if (type.equals(targetName)) {
                        map.put(targetName, args[k]);
                        flag = true;
                        break;
                    }
                }
                // 不是基础类型，为普通类
                if (!flag) {
                    // 通过反射获取实体类属性，getDeclaredFields获取private protected public修饰的字段
                    Field[] fields = args[k].getClass().getDeclaredFields();
                    for (Field field : fields) {
                        // 获取字段名称
                        String fieldName = field.getName();
                        field.setAccessible(true);
                        // 获取该字段属性的值
                        Object val = field.get(args[k]);
                        map.put(fieldName, val);
                    }
                }
                clazzMap.put(targetName, map);
            }
        } catch (IllegalAccessException e) {
            LOGGER.info("日志，获取参数异常");
        }
        return clazzMap;
    }

    /**
     * 异常增强，方法抛异常执行
     *
     * @param jp
     * @param e  异常信息
     * @return void
     * @author
     */
    @AfterThrowing(value = "pointCut()", throwing = "e")
    public void exceptionLog(JoinPoint jp, Exception e) {
        // 预设参数
        String params = "";
        try {
            Object[] args = jp.getArgs();
            if (null != args) {
                Map<String, Map> clazzMap = getArgsMap(args);
                params = JSON.toJSONString(clazzMap);
            }
            // 获取被织入增强处理的目标对象
            Object target = jp.getTarget();
            String clazz = target.getClass().getName();
            // 获取方法签名
            Signature signature = jp.getSignature();
            String method = signature.getName();
            LOGGER.error("[类:" + clazz + " 方法：" + method + "]\n入参：" + params + "\n异常：" + e);
        } catch (BusinessException ex) {
            LOGGER.info("切面异常");
        }
    }

}

